package cn.mandifal.search.service.impl;

import cn.mandifal.pojo.DpItem;
import cn.mandifal.search.service.SearchService;
import com.alibaba.dubbo.config.annotation.Service;
import org.apache.http.client.RedirectStrategy;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.data.solr.core.query.*;
import org.springframework.data.solr.core.query.result.GroupEntry;
import org.springframework.data.solr.core.query.result.GroupPage;
import org.springframework.data.solr.core.query.result.GroupResult;
import org.springframework.data.solr.core.query.result.ScoredPage;

import java.nio.MappedByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  检索服务实现层
 * @author shun
 */
@Service(timeout = 3000)
public class SearchServiceImpl implements SearchService {
    @Autowired
    private SolrTemplate solrTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     *  检索
     * @param searchMap 搜索实体，map 类型
     * @return 返回结果
     */
    @Override
    public Map search(Map searchMap) {
        Map map=new HashMap();
        //空格处理
        String keywords = (String) searchMap.get("keywords");
        //用空字符代替空格
        searchMap.put("keywords",keywords.replace(" ",""));
        //得到此关键字下的所有商品,并放入 map 中返回
        map.putAll(searchResult(searchMap));
        //得到此关键字下的所有分类，并放入 map 中返回
        List<String> categoryList= searchCategoryList(searchMap);
        map.put("categoryList",categoryList);
        //得到前台传过来的分类名称
        String category = (String) searchMap.get("category");
        //得到缓存中的品牌列表和规格列表,并放入 map 中
        if (!"".equals(category)){
            // 当 category 不=''，按照传入的值查询，并把结果放入map 中
            map.putAll(searchBrandListAndSpecList(category));
        }else{
            if(categoryList.size()>0){
                map.putAll(searchBrandListAndSpecList(categoryList.get(0)));
            }
        }
        return map;
    }

    /**
     * 得到搜索结果，抽取成方法
     * @param searchMap
     * @return
     */
    private Map searchResult(Map searchMap){
        Map map=new HashMap();
        //创建查询对象
        Query query=new SimpleQuery("*:*");
        //匹配条件
        //1.给查询添加条件
        Criteria criteria =new Criteria("item_keywords").is(searchMap.get("keywords"));
        query.addCriteria(criteria);
        //2.如果前台传来的 category 不为空，则添加分类过滤查询
        if (! "".equals(searchMap.get("category"))){
            //创建过滤查询条件
            Criteria filtercriteria = new Criteria("item_category").is(searchMap.get("category"));
            //创建过滤查询对象，传入条件
            FilterQuery filterQuery=new SimpleFilterQuery(filtercriteria);
            //把过滤查询对象添加到查询对象中
            query.addFilterQuery(filterQuery);
        }
        //3.判断前台传来的 brand 不为空，则添加品牌过滤查询
        if (!"".equals(searchMap.get("brand"))){
            Criteria filterBrandCriteria=new Criteria("item_brand").is(searchMap.get("brand"));
            FilterQuery filterBrandQuery=new SimpleFilterQuery(filterBrandCriteria);
            query.addFilterQuery(filterBrandQuery);
        }
        //4.将集合中的 spec key 对应的value 转换成 map 集合
        Map<String,String> specMap = (Map<String,String>) searchMap.get("spec");
        if (specMap.size()>0){
            //循环遍历 spec 中的 key
            for (String key:specMap.keySet()){
                Criteria filterSpecCriteria=new Criteria("item_spec_"+key).is(specMap.get(key));
                FilterQuery filterSpecQuery=new SimpleFilterQuery(filterSpecCriteria);
                query.addFilterQuery(filterSpecQuery);
            }
        }
        //5.按照价格区间筛选
        if (! "".equals(searchMap.get("price"))) {
            String price = (String) searchMap.get("price");
            //按照-切割，得到一个数组
            String[] prices = price.split("-");
            //如果区间起点不等于0
            if (!prices[0].equals("0")) {
                //greaterThanEqual(prices[0])数据类型会自动转换，不用特意的去转换成 long 类型
                Criteria filterPriceCriteria = new Criteria("item_price").greaterThanEqual(prices[0]);
                FilterQuery filterPriceQuery = new SimpleFilterQuery(filterPriceCriteria);
                query.addFilterQuery(filterPriceQuery);
            }
            //如果区间终点不等于*
            if(!prices[1].equals("*")){
                Criteria filterCriteria=new  Criteria("item_price").lessThanEqual(prices[1]);
                FilterQuery filterQuery=new SimpleFilterQuery(filterCriteria);
                query.addFilterQuery(filterQuery);
            }
        }
        //6.分页显示
        //得到页码
        Integer pageNum = (Integer) searchMap.get("pageNum");
        //如果没有默认为 1
        if (pageNum==null){
            pageNum=1;
        }
        //得到页面大小
        Integer pageSize = (Integer) searchMap.get("pageSize");
        //默认为 20
        if (pageSize==null){
            pageSize=20;
        }
        //设置起始点 公式为 （pageNum-1）*pageSize
        query.setOffset((pageNum-1)*pageSize);
        //设置查询记录数
        query.setRows(pageSize);
        //7按**排序
        //得到升序降序
        String sort= (String) searchMap.get("sort");
        //得到排序字段
        String sortField= (String) searchMap.get("sortField");
        if (sort!=null && "".equals(sort)){
            if (sort.equals("ASC")){
                //构建排序对象
                Sort sortObject=new Sort(Sort.Direction.ASC,"item_"+sortField);
                //把排序对象添加到搜索对象中
                query.addSort(sortObject);
            }
            if (sort.equals("DESC")){
                //构建排序对象
                Sort sortObject=new Sort(Sort.Direction.DESC,"item_"+sortField);
                //把排序对象添加到搜索对象中
                query.addSort(sortObject);
            }
        }
        //查询
        ScoredPage<DpItem> dpItems = solrTemplate.queryForPage(query, DpItem.class);
        //得到查询结果，并放入 map 集合中，为此 key 起名为 rows
        map.put("rows",dpItems.getContent());
        //得到总页数和总记录数
        map.put("totalPages",dpItems.getTotalPages());
        map.put("total",dpItems.getTotalElements());
        return map;
    }

    /**
     * 查询分类列表，抽取成方法
     * @param searchMap
     * @return
     */
    private List searchCategoryList(Map searchMap){
        //list 中包含分类信息
        List<String>list=new ArrayList<>();
        //得到查询对象,根据查询对象来查询
        Query query=new SimpleQuery();
        //按照关键字查询
        Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));
        query.addCriteria(criteria);
        //设置分组选项,类似于 sql 上写上 group by 语句
        GroupOptions groupOptions=new GroupOptions().addGroupByField("item_category");
        query.setGroupOptions(groupOptions);
        //实施查询,得到分组页面对象
        GroupPage<DpItem> page = solrTemplate.queryForGroupPage(query, DpItem.class);
        //得到分组结果对象，和分组页面对象不同就是分组页面可以添加多个分组列，所以分组页面对象中可能包含别的分组列的分组结果
        GroupResult<DpItem> groupResult = page.getGroupResult("item_category");
        //得到分组结果入口页，和分组页的区别就是此页只有一个列的分组结果
        Page<GroupEntry<DpItem>> groupEntries = groupResult.getGroupEntries();
        //得到分组入口集合
        List<GroupEntry<DpItem>> content = groupEntries.getContent();
        for (GroupEntry<DpItem> entry:content){
            //将分组结果的名称封装到返回值中
            list.add(entry.getGroupValue());
        }
        return list;
    }

    /**
     * 查询缓存，得到商品分类列表和商品规格列表
     * @param category 商品分类名称
     * @return
     */
    private Map searchBrandListAndSpecList(String category){
        Map map=new HashMap();
        //从缓存中得到key为商品分类名称，value 为商品模板id
        Long typeId= (Long) redisTemplate.boundHashOps("goodsCategory").get(category);
        if (typeId !=null){
            //根据模板 id 得到品牌列表
            List brandList = (List) redisTemplate.boundHashOps("brandList").get(typeId);
            map.put("brandList",brandList);
            //根据模板 id 得到规格列表
            List specList = (List) redisTemplate.boundHashOps("specList").get(typeId);
            map.put("specList",specList);
        }
        return map;
    }

    /**
     * 导入数据
     * @param list 需导入的数据
     */
    @Override
    public void importList(List list) {
        //导入需要导入的数据
        solrTemplate.saveBeans(list);
        //提交，增删改都要提交
        solrTemplate.commit();
    }

    /**
     * 从 solr 中删除
     * @param goodsIdList 待删除的商品spu id 列表
     */
    @Override
    public void deleteByGoodsIds(List goodsIdList) {
        Query query=new SimpleQuery();
        Criteria criteria=new Criteria("item_goodsId").in(goodsIdList);
        query.addCriteria(criteria);
        solrTemplate.delete(query);
        solrTemplate.commit();
    }

}
